package cn.iocoder.yudao.framework.jackson.core.databind;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;

import java.io.IOException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.regex.Pattern;

/**
 * LocalDateTime反序列化规则
 * <p>
 * 会将毫秒级时间戳反序列化为LocalDateTime
 */
public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {

    public static final LocalDateTimeDeserializer INSTANCE = new LocalDateTimeDeserializer();

    // 定义两个正则表达式用于匹配日期格式
    private static final Pattern PATTERN_DASH = Pattern.compile("^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$");
    private static final Pattern PATTERN_SLASH = Pattern.compile("^\\d{4}/\\d{2}/\\d{2} \\d{2}:\\d{2}:\\d{2}$");

    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    private static final DateTimeFormatter FORMATTER_SPECIAL = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");

    private static final DateTimeFormatter FORMATTER_DAY = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    @Override
    public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        String text = p.getText();


        // Check if the text can be parsed as a long value (epoch millis)
        try {
            long timestamp = Long.parseLong(text);
            return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault());
        } catch (NumberFormatException e) {
            // Not a long, try to parse as a string date-time
            if (text.length() == 10) {
                return LocalDate.parse(text, FORMATTER_DAY).atStartOfDay();
            } else {
                return LocalDateTime.parse(text, checkDateFormat(text));
            }
        }
    }

    private DateTimeFormatter checkDateFormat(String date) {
        if (PATTERN_DASH.matcher(date).matches()) {
            return FORMATTER;
        } else if (PATTERN_SLASH.matcher(date).matches()) {
            return FORMATTER_SPECIAL;
        } else {
            return DateTimeFormatter.ofPattern("");
        }
    }
}
